#include "fml_ota.h"
#include "fml_config.h"
#include "md_5.h"


OTA_INFO g_ota_info;
cJSON *g_ota_info_json = NULL;

int32_t fml_ota_init(void)
{
    cJSON *p_root = NULL;
    cJSON *p_item = NULL;
    uint8_t *str_buff = NULL;
    int32_t ret = 0;

    memset(&g_ota_info, 0, sizeof(g_ota_info));
    
    str_buff = (uint8_t *)malloc(FLASH_PAGE_SIZE);
    if (str_buff == NULL)
        return -1;
    
    hal_flash_read(str_buff, CONFIG_START_ADDR, FLASH_PAGE_SIZE);
    
    p_root = cJSON_Parse(str_buff);
    if (NULL == p_root)
    {
        printf("Parse OTA info obj failed\r\n");
        ret = -2;
        goto mem_free;
    }

    p_item = cJSON_GetObjectItem(p_root, "app_update_flag");
    if (NULL == p_item)
    {
        printf("Get app_update_flag item failed\r\n");
        ret = -3;
        goto mem_free;
    }
    else
    {
        g_ota_info.app_update_flag = p_item->valueint;
        printf("app_update_flag: %d\r\n", g_ota_info.app_update_flag);
    }
    
    p_item = cJSON_GetObjectItem(p_root, "app_version");
    if (NULL == p_item)
    {
        printf("Get app_version item failed\r\n");
        ret = -4;
        goto mem_free;
    }
    else
    {
        //strcpy(g_ota_info.app_version, p_item->valuestring);
        //printf("app_version:%s\r\n", g_ota_info.app_version);
    }
    
    p_item = cJSON_GetObjectItem(p_root, "app_md5");
    if (NULL == p_item)
    {
        printf("Get app_md5 item failed\r\n");
        ret = -5;
        goto mem_free;
    }
    else
    {
        strcpy(g_ota_info.app_md5, p_item->valuestring);
        printf("app_md5:%s\r\n", g_ota_info.app_md5);
    }

    p_item = cJSON_GetObjectItem(p_root, "json_data_md5");
    if (NULL == p_item)
    {
        printf("Get json_data_md5 item failed\r\n");
        ret = -6;
        goto mem_free;
    }
    else
    {
        strcpy(g_ota_info.json_data_md5, p_item->valuestring);
        printf("json_data_md5:%s\r\n", g_ota_info.json_data_md5);
    }

    g_ota_info_json = p_root;

mem_free:
    if (str_buff)
        free(str_buff);

    return ret;
}

int32_t fml_ota_json_to_otainfo(OTA_INFO *ota_info, cJSON *p_root)
{
    cJSON *p_item = NULL;
    
    if ((ota_info == NULL) || (p_root == NULL))
        return -1;
    
    p_item = cJSON_GetObjectItem(p_root, "update_flag");
    if (NULL == p_item)
    {
        printf("Get update_flag item failed\r\n");
        return -2;
    }
    ota_info->app_update_flag = p_item->valueint;
    
    p_item = cJSON_GetObjectItem(p_root, "app_md5");
    if (NULL == p_item)
    {
        printf("Get app_md5 item failed\r\n");
        return -2;
    }
    memset(ota_info->app_md5, 0, sizeof(ota_info->app_md5));
    strcpy(ota_info->app_md5, p_item->valuestring);
    
    p_item = cJSON_GetObjectItem(p_root, "app_size");
    if (NULL == p_item)
    {
        printf("Get app_size item failed\r\n");
        return -2;
    }
    ota_info->app_size = p_item->valueint;
    
    p_item = cJSON_GetObjectItem(p_root, "json_data_md5");
    if (NULL == p_item)
    {
        printf("Get json_data_md5 item failed\r\n");
        return -2;
    }
    memset(ota_info->json_data_md5, 0, sizeof(ota_info->json_data_md5));
    strcpy(ota_info->json_data_md5, p_item->valuestring);
    
    p_item = cJSON_GetObjectItem(p_root, "json_data_size");
    if (NULL == p_item)
    {
        printf("Get json_size item failed\r\n");
        return -2;
    }
    ota_info->json_data_size = p_item->valueint;
    
    return 0;
}

cJSON *fml_ota_otainfo_to_json(OTA_INFO *ota_info)
{
    cJSON *p_root = NULL;

    if (ota_info == NULL)
        return NULL;
    
    p_root = cJSON_CreateObject();
    if (p_root == NULL)
    {
        printf("Create json obj failed\r\n");
        return NULL;
    }
    
    printf("Add %s:%d item to obj\r\n", "update_flag", ota_info->app_update_flag);
    cJSON_AddNumberToObject(p_root, "update_flag", ota_info->app_update_flag);

    printf("Add %s:%s item to obj\r\n", "app_md5", ota_info->app_md5);
    cJSON_AddStringToObject(p_root, "app_md5", ota_info->app_md5);

    printf("Add %s:%d item to obj\r\n", "app_size", ota_info->app_size);
    cJSON_AddNumberToObject(p_root, "app_size", ota_info->app_size);
    
    printf("Add %s:%s item to obj\r\n", "json_data_md5", ota_info->json_data_md5);
    cJSON_AddStringToObject(p_root, "json_data_md5", ota_info->json_data_md5);

    printf("Add %s:%d item to obj\r\n", "json_data_size", ota_info->json_data_size);
    cJSON_AddNumberToObject(p_root, "json_data_size", ota_info->json_data_size);
    
    return p_root;
}

int32_t fml_ota_set_ota_info(bool update_flag, uint8_t *app_md5, uint32_t app_size)
{
    uint8_t *p_json = NULL;
    int32_t ret = 0;
    
    g_ota_info.app_update_flag = update_flag;
    strncpy(g_ota_info.app_md5, app_md5, 32);
    g_ota_info.app_size = app_size;
    
    p_json = fml_config_to_json(&g_dev_info, &g_ota_info);
    if (p_json == NULL)
        return -2;
    
    if (hal_flash_erase(CONFIG_START_ADDR, CONFIG_SIZE) < 0)
    {
        ret = -3;
        goto out;
    }
    
    hal_flash_write(p_json, CONFIG_START_ADDR, strlen(p_json));

out:
    if (p_json)
        free(p_json);
    
    return ret;
}

int32_t fml_ota_app_md5_calc(uint32_t addr, int32_t len, uint8_t *md5_out)
{
	MD5_CTX_T ctx;
	uint8_t i = 0;
	int32_t cur = 0, calc_len = 0;
	//uint8_t md5[32] = {0};
	uint8_t *p_calc = (uint8_t *)malloc(512);
    
	if (p_calc == NULL)
    {
        printf("malloc mem for md5 calc fail\r\n");
		return -1;
	}
    
	if (len <= 0)
    {
		printf("get a err len for data to check md5\r\n");
		return -1;
	}
    
	calc_len = len;
	md5_init(&ctx);
	while (true)
    {
		calc_len = len - cur;
		if (calc_len >= 512)
        {
			//GD_read_fast(p_calc, addr + cur, 512);
            hal_flash_read(p_calc, addr + cur, 512);
			md5_update(&ctx, p_calc, 512);
		} 
		else
        {
			//GD_read_fast(p_calc, addr + cur, calc_len);
            hal_flash_read(p_calc, addr + cur, calc_len);
			md5_update(&ctx, p_calc, calc_len);
			break;
		}
		memset(p_calc, 0, 512);
		cur += 512;
	}
    
	md5_final(&ctx, md5_out);
    
	//for (i = 0; i < 16; i++)
	//	sprintf((char *)md5_out + 2 * i, "%02x", md5[i]);

	free(p_calc);

	return 0;
}
